package br.com.marcio.obj;

import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.media.opengl.DebugGL2;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;
import javax.swing.JFrame;

import com.jogamp.opengl.util.Animator;

public class Main extends GLCanvas implements GLEventListener, KeyListener, MouseListener, MouseWheelListener {
	private static final long serialVersionUID = 1L;
	static JFrame frame;
	
	private static final int DESLOCAMENTO = 10;
    private static final int BUFSIZE = 1024;
    private GL2 gl;
    private GLU glu;
    private GLAutoDrawable glDrawable;
    private double fAspect;
    private float angulo;
    private boolean[] direcoes;
    private int fps = 60;
    private Animator animator;
    private Mesh mesh;
    private Point pickPoint; // Ponto do clique
    private float camX;
    private float camY;
    private float camZ;
    private float centerX;
    private float centerY;
    private float centerZ;
	
    public Main(GLCapabilities capabilities, int width, int height){
        addGLEventListener(this);
        addKeyListener(this);
        addMouseListener(this);
        addMouseWheelListener(this);

        direcoes = new boolean[2];
        for (int i = 0; i < direcoes.length; i++) {
            direcoes[i] = false;
        }

        // Inicializa o valor para correção de aspecto
        fAspect = width / height;

        camX = 0.0f;
        camY = 50.0f;
        camZ = -50.0f;

        centerX = 0;
        centerY = 0;
        centerZ = 0;

    }
    
    public static GLCapabilities createGLCapabilities(){
        GLCapabilities capabilities = new GLCapabilities(GLProfile.getDefault());
        capabilities.setRedBits(8);
        capabilities.setBlueBits(8);
        capabilities.setGreenBits(8);
        capabilities.setAlphaBits(8);
        return capabilities;
    }
    
    
    public static void main(String[] args) {
        GLProfile glp = GLProfile.getDefault();
        GLCapabilities caps = new GLCapabilities(glp);
        GLCanvas canvas = new GLCanvas(caps);

        GLCapabilities capabilities = createGLCapabilities();
        Main janela = new Main(capabilities, 800, 500);
        frame = new JFrame("OBJ");
        frame.getContentPane().add(janela, BorderLayout.CENTER);
        frame.setSize(800, 500);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        canvas.requestFocus();

        Animator animator = new Animator(canvas);
        //animator.add(canvas);
        animator.start();
    }
    
    public void camera(){
        // Especifica sistema de coordenadas de projeção
        gl.glMatrixMode(GL2.GL_PROJECTION);
        // Inicializa sistema de coordenadas de projeção
        gl.glLoadIdentity();

        // Especifica a projeção perspectiva(angulo,aspecto,zMin,zMax)
        glu.gluPerspective(45, fAspect, 0.2, 1500);

        glu.gluLookAt(camX, camY, camZ, centerX, centerY, centerZ, 0.0f, 1.0f, 0.0f);

        // Especifica sistema de coordenadas do modelo
        gl.glMatrixMode(GL2.GL_MODELVIEW);
        // Inicializa sistema de coordenadas do modelo
        gl.glLoadIdentity();
    }

    public void iluminacao(){
        float[] position = {0.0f, 1.0f, 1.0f, 1.0f};
        gl.glLightfv(GL2.GL_LIGHT0, GL2.GL_POSITION, position, 0);
    }
    
    private void drawObject(int mode){
        if(direcoes[0]) angulo += 10;
        if(direcoes[1]) angulo -= 10;

        gl.glPushMatrix();
            gl.glRotatef(angulo, 0.0f, 1.0f, 0.0f);
            for (int i = 0; i < mesh.getGrupos().size(); i++) {
                Group g = mesh.getGrupos().get(i);

                if(mode == GL2.GL_SELECT)
                    gl.glPushName(g.getIndex());

                for (int j = 0; j < g.getFaces().size(); j++) {
                    Face f = g.getFaces().get(j);

                    gl.glBegin(GL2.GL_POLYGON);
                    if(g.isSelected()) {
                        gl.glColor3f(1.0f, 1.0f, 0.0f);
                    } else {
                        gl.glColor3f(0.0f, 0.5f, 0.7f);
                    }

//                    Material material = mesh.getMaterial(f.getMaterialName());

                    // null - se não conseguiu carregar o mtl
//                    if(material != null) {
//                        gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, material.getKa(), 0);
//                        gl.glMaterialfv(GL.GL_FRONT, GL.GL_DIFFUSE, material.getKd(), 0);
//                        gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, material.getKs(), 0);
//                    }

                    for (int k = 0; k < f.getVertexes().size(); k++) {

                        Vertex normal = f.getNormals().get(k);
                        if(normal != null)
                          gl.glNormal3f(normal.getX(), normal.getY(), normal.getZ());
//                        TextureMapping textureMapping = f.getTexturesMapping().get(k);
//                        if(textureMapping != null)
//                          gl.glTexCoord2f(textureMapping.getX(), textureMapping.getY());
                        Vertex vertex = f.getVertexes().get(k);
                        gl.glVertex3f(vertex.getX(), vertex.getY(), vertex.getZ());
                    }
                    gl.glEnd();
                }

                if(mode == GL2.GL_SELECT)
                    gl.glPopName();
                
            }
        gl.glPopMatrix();
    }
    
//    public void picking(){
//        int selectBuf[] = new int[BUFSIZE];
//        IntBuffer selectBuffer = BufferUtil.newIntBuffer(BUFSIZE);
//        int hits;
//        int viewport[] = new int[4];
//
//        gl.glSelectBuffer(BUFSIZE, selectBuffer);
//
//        gl.glGetIntegerv(GL2.GL_VIEWPORT, viewport, 0);
//
//        gl.glRenderMode(GL2.GL_SELECT);
//
//        gl.glInitNames();
//
//        gl.glMatrixMode(GL2.GL_PROJECTION);
//        gl.glPushMatrix();
//        gl.glLoadIdentity();
//
//        /* create 5x5 pixel picking region near cursor location */
//        glu.gluPickMatrix((double) pickPoint.x,
//            (double) (viewport[3] - pickPoint.y),
//            5.0, 5.0, viewport, 0);
//        float ratio = viewport[2] / viewport[3];
//        glu.gluPerspective(45,ratio,0.1,1000);
//        gl.glMatrixMode(GL2.GL_MODELVIEW);
//
//        drawObject(GL2.GL_SELECT);
//        
//        gl.glMatrixMode(GL2.GL_PROJECTION);
//        gl.glPopMatrix();
//        gl.glMatrixMode(GL2.GL_MODELVIEW);
//        gl.glFlush();
//
//        hits = gl.glRenderMode(GL2.GL_RENDER);
//        selectBuffer.get(selectBuf);
//        if(hits != 0) {
//            processHits(hits, selectBuf);
//        }
//    }
//----------------------------------------------------GLEventLister----------------------------------------------------
	@Override
	public void init(GLAutoDrawable drawable) {
		glDrawable = drawable;
		gl = drawable.getGL().getGL2();
		glu = new GLU();
		
		glDrawable.setGL(new DebugGL2(gl));
		
		gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		gl.glEnable(GL2.GL_DEPTH_TEST);
		
		// habilita luz
        gl.glEnable(GL2.GL_LIGHTING);
        gl.glEnable(GL2.GL_LIGHT0);
        
        // Habilita o modelo de colorização de Gouraud
        gl.glShadeModel(GL2.GL_FLAT);
		
        //configuraTextura();

        animator = new Animator();
        animator.start();
        
        try {
        	//mesh = OBJReader.readOBJ("obj/esqueleto.obj");
            mesh = OBJReader.readOBJ("obj/esqueletoPernas.obj");
        	//mesh = OBJReader.readOBJ("/home/marcio/Área de trabalho/dragon.obj");
        } catch(Exception e) {
            e.printStackTrace();
            System.exit(-1);
        }
	}
	
	@Override
	public void display(GLAutoDrawable arg0) {
		 gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT );
		 
//		 if (pickPoint != null) {
//	         picking();
//	         pickPoint = null;
//	     }
		 
		 gl.glLoadIdentity();
		 
		 camera();
		 
		 iluminacao();
		 
		 drawObject(GL2.GL_RENDER);
	}
	
	@Override
	public void reshape(GLAutoDrawable arg0, int arg1, int arg2, int arg3,
			int arg4) {
		drawObject(GL2.GL_RENDER);
		// TODO Auto-generated method stub
		
	}
	
	@Override
	public void dispose(GLAutoDrawable arg0) {
		// TODO Auto-generated method stub
		
	}
//----------------------------------------------------KeyListener----------------------------------------------------
    @Override
    public void keyPressed(KeyEvent e)
    {
    	System.out.println(e.getKeyCode());
        switch (e.getKeyCode())
        {
            case KeyEvent.VK_LEFT:
                direcoes[0] = true;
                System.out.println("Esquerda");
                break;
            case KeyEvent.VK_RIGHT:
                direcoes[1] = true;
                System.out.println("Direita");
                break;
        }
    }
    @Override
    public void keyReleased(KeyEvent e){
        switch (e.getKeyCode())
        {
            case KeyEvent.VK_LEFT:
                direcoes[0] = false;
                break;
            case KeyEvent.VK_RIGHT:
                direcoes[1] = false;
                break;
            case KeyEvent.VK_D:
                camX -= DESLOCAMENTO;
                break;
            case KeyEvent.VK_A:
                camX += DESLOCAMENTO;
                break;
            case KeyEvent.VK_S:
                camY -= DESLOCAMENTO;
                break;
            case KeyEvent.VK_W:
                camY += DESLOCAMENTO;
                break;
            case KeyEvent.VK_Q:
                camZ -= DESLOCAMENTO;
                break;
            case KeyEvent.VK_E:
                camZ += DESLOCAMENTO;
                break;
            case KeyEvent.VK_H:
                centerX -= DESLOCAMENTO;
                break;
            case KeyEvent.VK_F:
                centerX += DESLOCAMENTO;
                break;
            case KeyEvent.VK_G:
                centerY -= DESLOCAMENTO;
                break;
            case KeyEvent.VK_T:
                centerY += DESLOCAMENTO;
                break;
            case KeyEvent.VK_Y:
                centerZ -= DESLOCAMENTO;
                break;
            case KeyEvent.VK_R:
                centerZ += DESLOCAMENTO;
                break;
        }
    }
    @Override
    public void keyTyped(KeyEvent e){}
    
//----------------------------------------------------MouseLister----------------------------------------------------
    @Override
    public void mouseClicked(MouseEvent e){}
    @Override
    public void mousePressed(MouseEvent e){}
    @Override
    public void mouseReleased(MouseEvent e){
        switch (e.getButton()) {
		case MouseEvent.BUTTON1:
			System.out.println("Botão 1");
	        pickPoint = e.getPoint();
	        //display();
			break;
		case MouseEvent.BUTTON2:
			System.out.println("Botão 2");
			break;
		case MouseEvent.BUTTON3:
			System.out.println("Botão 3");
			break;
		default:
			break;
		}
    }
    @Override
    public void mouseEntered(MouseEvent e){}
    @Override
    public void mouseExited(MouseEvent e){}
    
//----------------------------------------------------MouseWheelListner----------------------------------------------------
	@Override
	public void mouseWheelMoved(MouseWheelEvent arg0) {
		switch (arg0.getWheelRotation()) {
		case -1:
			System.out.println("UP!");
			camX=(camX>0)?camX-1:camX+1;
			camY=(camY>0)?camY-1:camY+1;
			camZ=(camZ>0)?camZ-1:camZ+1;
			break;
		case 1:
			System.out.println("Down!");
			camX=(camX>0)?camX+1:camX-1;
			camY=(camY>0)?camY+1:camY-1;
			camZ=(camZ>0)?camZ+1:camZ-1;

			break;
		default:
			System.out.println("Movimento wheel não identificado");
			break;
		}
	}
}
